def introduce(name,age):
    print(f"我叫{name},今年{age}岁")
introduce("小猫",11)
#introduce(age=11,name="xiaomao")
#关键字参数和位置参数混合使用时，位置参数必须要在关键字参数之前
#introduce("小猫",age=11)

#默认值参数
def introduce2(name,age=18):
    print(f"我叫{name},今年{age}岁")

introduce2('小猫')
introduce2('小猫',20)


'''

函数：
函数是封装了特定功能的可重复使用的代码块，它让程序更清晰，避免重复，便于测试和维护
函数的好处：修改只需要修改一处
逻辑清晰，并且可读性强
可以被其他的模块导入并且重复的使用

函数四大类型：
1.内置函数：python自带  print  len   int    type
2.标准库函数： python的标准库  json     random   需要使用import 导入
3.第三方的函数   python社区开发的，需要我们 使用 pip  install 来下载之后再使用  import导入使用
4.自定义的函数  用户自己编写的   不需要导入
'''

# print("小兔子乖乖")
# print('把门打开')
# .........N  使代码膨胀

# def sing_rabbit_song():
#     print("小兔子乖乖")
#     print('把门打开')
# sing_rabbit_song()
# sing_rabbit_song()
# sing_rabbit_song()
# sing_rabbit_song()


#内置函数
# text = 'Hello'
# print(len(text))
# print(type(text))


#标准库函数
# import math
#
# print(math.pi)   # pi使表示 圆周率
# print(math.sqrt(25))   # sqrt  计算了25的平方根


#第三方的函数

# import  numpy as np  #做科学运算的库
# arr = np.zeros(3)
# print(arr)


#自定义的函数
#
# def greet(name):
#     return f"Hello,{name}!"   # 这个name 是一个形参，allen是实参
# print(greet('Allen'))
#
# """
# 社么是形参，什么是实参
# 形参：函数内部用来接收外部传入的变量名称
# 实参:传递给函数具体的值
# 函数的基本语法

# def 函数名称(参数的列表):
#     函数体
#     [reture   返回值]



# def say_hello():
#     print("hello")
# say_hello()

"""
扩展：函数是对象的一等公民
再python中，函数是function类型的对象
他可以，赋值给变量，作为参数进行传递，作为返回值，存放数据结构
"""

#赋值给变量

# def greet():  # 创建一个函数
#     return "Hi"    #命名返回值 为 Hi
# f = greet
# print(f())


# def call_twice(func):    # 是一个高阶的函数，接收另一个函数作为参数
#     func()  #第一次调用传入的函数
#     func()  #第二次调用传入的函数
#
# def hello():   # 0x000002764101DAF0 在内存中的一个地址，是一个十六进制
#     print("Hello")
#
# # call_twice(hello)   # 是使用了 call_twice 调用了 hello 来输出
# # print(type(hello))
# print(hello)


# def exector(function_to_run):
#     print("准备执行函数....")
#     function_to_run()
#     print("函数执行完毕！")
# def say_hello():
#     print('Hello!')
# def say_goodbye():
#     print('Goodbye')
# exector(say_hello)
# exector(say_goodbye)

"""
准备执行函数
Hello
函数执行完毕
准备执行函数
Goodbye
函数执行完毕

"""

#
# def executor(function_to_run):   #高阶函数，可以接收其他函数的值
#     print("准备执行函数")
#     function_to_run()
#     print("函数执行完毕")
# def say_hello():
#     print("Hello")
#
# executor(say_hello)


#参数
#位置参数：按照定义的顺序传入

# def introduce(name,age):
#     print(f"我叫{name},今年{age}岁。")
# # introduce("小明",12)  #可运行
# introduce(12,"小明")  #逻辑错误，但是可以运行


#关键字参数

# def introduce(name,age):
#     print(f"我叫{name},今年{age}岁。")
# introduce(age=15,name='小明')   #  关键字，age，name

# introduce('小明',age=16)
# introduce(age=16,'小明')   # SyntaxError: positional argument follows keyword argument

#关键字参数和位置参数  混合使用时，位置参数必须要在关键字参数之前


#默认值参数 必须排在非默认值之后

def introduce(name,age=18):
    print(f"我叫{name},今年{age}岁。")

# introduce('小明')
introduce('小明',20)


#任意多个位置参数 *args
#收集多余的位置参数为元组
#收集数字
def sum_all(*numbers):
    print("收到的参数",numbers)
    return sum(numbers)
print(sum_all(1,2,3))

#任意多个关键字参数 **kwargs
##收集多余的参数为字典
def print_user_info(**info):
    print("用户信息")
    for key, value in info.items():
        print(f"{key}:{value}")
print_user_info(name="wa",age=18)

#强制命名参数  星号之后的值必须关键字参数传递  提高api的可读性和安全性 避免传参的顺序错误
def connect(host,*,port,timeout):
    print(f"链接{host}:{port},超时{timeout}秒")
connect("192.168.1.1",port=80,timeout=5)

"""
位置参数---默认参数---*args---**kwargs

"""

#返回值
def add(a,b):
    return a+b
result = add(1,2)
print(result)

#变量的作用域 LEGB
"""
py查找变量的顺序
local:当前函数的内部
enclosing：外层函数 比如嵌套函数
Global：模块级别
built-in，print len
"""
x = "全局变量"
def outer():
    x = '外层变量'
    def inner():
        x = '局部变量'
        print('inner 打印x',x)   #local
    inner()
outer()
"""
输出局部：inner中定义x
输出外层： inner不定义
输出全局：outer inner都不定义

"""

#修改变量

counter = 0  #在模块顶层定义了一个变量counter 他是一个全局变量
def increment():
    # 使用global方法 进行声明 要操作的变量是全局的counter
    #不使用global的话 counter就是一个全新的变量（还没定义）
    global counter
    counter += 1
increment()
print(counter)

"""
py中 如果使用赋值（= += -=） py会默认它是一个局部变量 除非用global声明

"""
counter1 = 0
def show():
    print(counter1)
show()

counter2 = 0
#def show2():
#   counter2 += 1
#show2()

"""
如果仅读取 不需要global
如果想修改 需要

"""

#修改外层变量
def outer2():
    x = 10
    def inner():
       nonlocal x
       x = 20
    inner()
    return x
print(outer2())


#查看变量 locals()

name = '全局变量'
def dome():
    age = 20
    score = 90
    print("局部变量",locals())  #返回一个字典 包含当前局部作用域中所有变量名和值
#locals 查看当前函数中的局部变量 返回一个字典
    print("全局变量",list(globals().keys())[:10])
    # globals 返回一个字典 包含当前全局的作用域 所有的变量，函数，类，导入的对象以及名称
    #globals().keys()获取所有的全局名称
    #list(...)[:5] #获取前五个
dome()

"""
数据分为可变和不可变
不可变：int str syuple
可变： list dict set


"""
#函数不能重名 覆盖容易引发逻辑问题














